﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using ScrumTable.Common;
using ScrumTable.Common.Collections;
using ScrumTable.Common.EventHandling;
using ScrumTable.UI.ViewModel.Data;
using Microsoft.Practices.Unity;
using ScrumTable.UI.ViewModel.Extension;

#endregion

namespace ScrumTable.UI.ViewModel
{
    /// <summary>
    /// Types of Scrum poker cards.
    /// </summary>
    public enum ScrumPokerCardType
    {
        /// <summary>
        /// Number Card
        /// </summary>
        Number = 0,
        /// <summary>
        /// Question Card
        /// </summary>
        Question = 1,
        /// <summary>
        /// Coffee Card
        /// </summary>
        CoffeeBreak = 2
    }

    /// <summary>
    /// Class representing a scrum poker card.
    /// </summary>
    public class ScrumPokerCard : NotifyPropertyChanged
    {
        #region Declarations

        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------
        /// <summary>
        /// All possible values of Scrum Poker Number cards
        /// </summary>
        public static double[] PossibleValues = {0, 0.5, 1, 2, 3, 5, 8, 13, 20, 40, 100};

        private readonly static List<Color> ColorList = new List<Color>() { Colors.Red, Colors.Green, Colors.Blue, Colors.Magenta, Colors.Orange, Colors.Cyan, Colors.Sienna, Colors.BlueViolet, Colors.PeachPuff, Colors.OliveDrab, Colors.Navy, Colors.Orchid, Colors.YellowGreen, Colors.SkyBlue, Colors.HotPink};
        private const int CardsPerSet = 20;
        private const int CardIndexCoffee = 19;
        private const int CardIndexQuestion = 18;

        private static readonly Pair<Color, Color> ColorSegement1 = new Pair<Color, Color>(ColorExtensions.ColorFromString("#FF00B400"), ColorExtensions.ColorFromString("#FFA2EB8E"));
        private static readonly Pair<Color, Color> ColorSegement2 = new Pair<Color, Color>(ColorExtensions.ColorFromString("#FFA2EB8E"), ColorExtensions.ColorFromString("#FFCAF900"));
        private static readonly Pair<Color, Color> ColorSegement3 = new Pair<Color, Color>(ColorExtensions.ColorFromString("#FFCAF900"), ColorExtensions.ColorFromString("#FFEBAC8E"));
        private static readonly Pair<Color, Color> ColorSegement4 = new Pair<Color, Color>(ColorExtensions.ColorFromString("#FFEBAC8E"), ColorExtensions.ColorFromString("#FF950000"));

        private bool _isHidden = false;

        #endregion

        #region Properties

        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------

        /// <summary>
        /// Gets or sets the color.
        /// </summary>
        /// <value>The color.</value>
        public Brush Color { get; set; }

        /// <summary>
        /// Gets or sets the card value.
        /// </summary>
        /// <value>The card value.</value>
        public ScrumPokerCardType CardType { get; set; }

        /// <summary>
        /// Gets or sets the number.
        /// </summary>
        /// <value>The number.</value>
        public double Number { get; set; }

        /// <summary>
        /// Gets or sets the identity tag value.
        /// </summary>
        /// <value>The identity tag value.</value>
        public long IdentityTagValue { get; set; }

        /// <summary>
        /// Reprsents how many times this card is placed on the field like Planning Poker
        /// </summary>
        public int Count { get; set; }


        /// <summary>
        /// If true, this card represents a dummy card (empty/null/whatelse)
        /// </summary>
        public bool IsDummyCard { get; set; }


        /// <summary>
        /// Set if this card is face-down (point value is not shown)
        /// </summary>
        public bool IsHidden
        {
            get { return _isHidden; }
            set
            {
                _isHidden = value;
                SendPropertyChanged("IsHidden");
            }
        }

        #endregion

        #region Methods

        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------
        /*
/// <summary>
/// Creates a ScrumPokerCard for identity tag value.
/// </summary>
/// <param name="identityTagValue">The identity tag value.</param>
/// <returns>new ScrumPokerCard</returns>

public static ScrumPokerCard CreateForIdentityTagValue(long identityTagValue)
{
    var res = new ScrumPokerCard {IdentityTagValue = identityTagValue};

    var lValue = (int) (identityTagValue & 0x000000000000000F);
    if (Enum.IsDefined(typeof (ScrumPokerCardType), lValue))
        res.CardType = (ScrumPokerCardType) Enum.ToObject(typeof (ScrumPokerCardType), lValue);
    else
        res.CardType = ScrumPokerCardType.Number;

    var lNumber = (identityTagValue & 0x0000000000000FF0) >> 4;
    var iNumber = (int) lNumber;
    res.Number = iNumber/2.0;

    var r = (byte) ((identityTagValue & 0x0000000FF0000000) >> (4*7));
    var g = (byte) ((identityTagValue & 0x000000000FF00000) >> (4*5));
    var b = (byte) ((identityTagValue & 0x00000000000FF000) >> (4*3));


    res.Color = new SolidColorBrush(System.Windows.Media.Color.FromRgb(r, g, b));

    return res;
}
*/



        /// <summary>
        /// Creates a ScrumPokerCard for identity tag value.
        /// </summary>
        /// <param name="byteTagValue">The byte tag value.</param>
        /// <returns>new ScrumPokerCard</returns>
        public static ScrumPokerCard CreateForByteTagvalue(long byteTagValue)
        {
            var res = new ScrumPokerCard { IdentityTagValue = byteTagValue };
            byteTagValue = byteTagValue % 255;

            long numberIndex = byteTagValue%CardsPerSet;
            res.Number = PossibleValues.Length > numberIndex ? PossibleValues[numberIndex] : 0;

            res.Color = new SolidColorBrush(ColorList[(int)Math.Floor(byteTagValue / (double)CardsPerSet)]);

            if (byteTagValue == CardIndexCoffee)
            {
                res.CardType = ScrumPokerCardType.CoffeeBreak;
            }
            else if( byteTagValue == CardIndexQuestion)
            {
                res.CardType = ScrumPokerCardType.Question;
            }
            else
            {
                res.CardType = ScrumPokerCardType.Number;
            }
            return res;
        }

        /// <summary>
        /// Creates the cards for the domain
        /// </summary>
        /// <returns></returns>
        public static ObservableCollection<ScrumPokerCard> CreateCardsForDomain()
        {

            ObservableCollection<ScrumPokerCard> allCards = new ObservableCollection<ScrumPokerCard>();
            var domainMeta = (((IAppScreen) Application.Current.MainWindow).Container.Resolve<ScrumViewModelData>()).CurrentProject.Types.UserStoryType.FieldMeta.TryGetByName("StoryPoints");
            double[] values = null;
            if (domainMeta != null && !domainMeta.SuggestedValues.IsEmpty())
            {
                if (domainMeta.SuggestedValues.ToEnumerable<object>().First() is double)
                {
                    var items = (from x in domainMeta.SuggestedValues.ToEnumerable<double>() select x).ToArray();
                    values = items;
                }
            }
            if (values == null)
            {
                values = PossibleValues;
            }

            for (int index = 0; index < values.Length; index++)
            {
                var value = values[index];
                var card = new ScrumPokerCard
                               {
                                   CardType = ScrumPokerCardType.Number,
                                   Number = value,
                                   Color = GetColorForValue(index, values.Count()) //System.Windows.Media.Colors.White
                               };
                allCards.Add(card);
            }
            return allCards;
        }



        public static Brush GetColorForValue(double current, double maxValue)
        {
            if (Math.Abs(current - 0.0) < 0.01)
            {
                return Brushes.LightGray;
            }
            double percent = current/maxValue;

            //Gets the color segement 
            Pair<Color, Color> currentSegment = GetSegment(percent);

            //Calculates the relativ position in each segement. 
            percent = (1/(Math.Ceiling(maxValue/4)))*(current%Math.Ceiling(maxValue/4));
            var valueR = currentSegment.Left.R - (currentSegment.Left.R - currentSegment.Right.R)*(percent);
            var valueG = currentSegment.Left.G - (currentSegment.Left.G - currentSegment.Right.G)*(percent);
            var valueB = currentSegment.Left.B - (currentSegment.Left.B - currentSegment.Right.B)*(percent);

            return new SolidColorBrush(System.Windows.Media.Color.FromRgb((byte) valueR, (byte) valueG, (byte) valueB));
        }


        private static Pair<Color, Color> GetSegment(double percent)
        {
            Pair<Color, Color> currentPair;
            if (percent < 0.25)
            {
                currentPair = ColorSegement1;
            }
            else if (percent < 0.50)
            {
                currentPair = ColorSegement2;
            }
            else if (percent < 0.75)
            {
                currentPair = ColorSegement3;
            }
            else
            {
                currentPair = ColorSegement4;
            }
            return currentPair;
        }

        #endregion

        #region Equals
        public bool Equals(ScrumPokerCard other)
        {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;
            return other.IdentityTagValue == IdentityTagValue && other.Number.Equals(Number) && other.IsDummyCard == IsDummyCard;
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != typeof (ScrumPokerCard)) return false;
            return Equals((ScrumPokerCard) obj);
        }

        public override int GetHashCode()
        {
            unchecked
            {
                return (IdentityTagValue.GetHashCode()*397) ^ Number.GetHashCode();
            }
        }
        #endregion
    }
}